/****************************************Copyright (c)*************************
**                               版权所有 (C), 2020-2030, 零匙科技
**
**                                 https://www.0k.com/
**
**
**-----------------------------------------------------------------------------
**--------------当前版本修订---------------------------------------------------
** 版  本: v1.0.0
** 日　期: 2022年02月15日
** 描　述: 1:协议初版
** 作  者：zouchuan
**-----------------------------------------------------------------------------
******************************************************************************/

#include "leokey_ble.h"
#include "hal_debug.h"
#include "systick.h"


#ifdef SUPPORT_MCU_RTC_CHECK
    const unsigned char mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};    //平年
    unsigned char timestamp[4];    //时间戳
    _calendar_obj _time;           //storage time   
#endif


//============================================================================= 
volatile unsigned char leokey_ble_queue_buf[PROTOCOL_HEAD + LEOKEY_BLE_UART_QUEUE_LMT];        //串口队列缓存
volatile unsigned char leokey_ble_uart_rx_buf[PROTOCOL_HEAD + LEOKEY_BLE_UART_RECV_BUF_LMT];   //串口接收缓存
volatile unsigned char leokey_ble_uart_tx_buf[PROTOCOL_HEAD + LEOKEY_BLE_UART_SEND_BUF_LMT];   //串口发送缓存

volatile unsigned char   rx_in;          //接收字节标志
volatile unsigned short  rx_length;      //接收数据长度



/*****************************************************************************
函数名称 : set_leokey_ble_uart_byte
功能描述 : 写leokey_ble_uart字节
输入参数 : dest:缓存区其实地址;长度
           byte:写入字节值；数据
返回参数 : 写入完成后的总长度
*****************************************************************************/
unsigned short set_leokey_ble_uart_byte(unsigned short dest, unsigned char byte)
{
    unsigned char *obj = (unsigned char *) leokey_ble_uart_tx_buf + DATA_START + dest;//Barry：+7;

    *obj = byte;
    dest += 1;

    return dest;
}

/*****************************************************************************
函数名称 : set_leokey_ble_uart_buffer
功能描述 : 写leokey_ble_uart_buffer
输入参数 : dest:目标地址
           src:源地址
           len:数据长度
返回参数 : 无
*****************************************************************************/
unsigned short set_leokey_ble_uart_buffer(unsigned short dest, unsigned char *src, unsigned short len)
{
    unsigned char *obj = (unsigned char *) leokey_ble_uart_tx_buf + DATA_START + dest;//Barry：+7;

    my_memcpy(obj, src, len);

    dest += len;
    return dest;
}


//============================================================================
//============================================================================


/*****************************************************************************
函数名称 : leokey_ble_uart_write_data
功能描述 : 向leokey_ble uart写入连续数据
输入参数 : in:发送缓存指针
           len:数据发送长度
返回参数 : 无
*****************************************************************************/
void leokey_ble_uart_write_data(unsigned char *in, unsigned short len)
{
    if ((NULL == in) || (0 == len))
    {
        return;
    }

    
    Hexdump_Debug(in, len, ' ');
    
    while (len--)
    {
        uart_transmit_output(*in);
        in++;
    }
}


/*****************************************************************************
函数名称 : get_check_sum
功能描述 : 计算校验和
输入参数 : pack:数据源指针
           pack_len:计算校验和长度
返回参数 : 校验和
*****************************************************************************/
unsigned char get_check_sum(unsigned char *pack, unsigned short pack_len)
{
    
    uint8_t i = 0;
    uint16_t sum = 0;
    
    for(i = 0; i < pack_len; i++)
    {
        sum += pack[i];
    }
    
    return (uint8_t)sum;
}


/*****************************************************************************
函数名称 : leokey_ble_uart_write_frame
功能描述 : 向leokey_ble串口发送一帧数据
输入参数 : fr_type:帧类型
           len:数据长度
返回参数 : 无
*****************************************************************************/


void leokey_ble_uart_write_frame(unsigned char fr_cmd, unsigned short len)
{
    unsigned char check_sum = 0;

    if ((fr_cmd == LEOKEY_BLE_ADV_CMD) ||  //前导码唤醒
        (fr_cmd == FACTORY_RESET_CMD)  ||
        (fr_cmd == LEOKEY_BLE_MASTER_QUERY)  ||
        (fr_cmd == GET_USER_KEY))    
    {
        mcu_wakeup_leokey_ble();        
    }

    leokey_ble_uart_tx_buf[HEAD_FIRST ] = 0x55;
    leokey_ble_uart_tx_buf[HEAD_SECOND ] = 0xaa;
    leokey_ble_uart_tx_buf[PROTOCOL_VERSION ] = VERSION;


    leokey_ble_uart_tx_buf[SEQUENCEH ] = 0x00;
    leokey_ble_uart_tx_buf[SEQUENCEL ] = 0x00;
    

    leokey_ble_uart_tx_buf[FRAME_CMD ] = fr_cmd;
    leokey_ble_uart_tx_buf[LENGTH ] = len >> 8;
    leokey_ble_uart_tx_buf[LENGTL ] = len & 0xff;

    len += PROTOCOL_HEAD;

    check_sum = get_check_sum((unsigned char *) leokey_ble_uart_tx_buf, len);
    
    LeoKey_Printf("tx len = %d ,check_sum = 0x%x \r\n", len, check_sum);
    
    leokey_ble_uart_tx_buf[len ] = check_sum;

    leokey_ble_uart_write_data((unsigned char *) leokey_ble_uart_tx_buf, len + 1);
}

//============================================================================
//============================================================================




/*****************************************************************************
函数名称 : mcu_wakeup_leokey_ble
功能描述 : 唤醒leokey_ble模块函数,任意串口数据都可唤醒BLE
输入参数 : 无
返回参数 : 无
*****************************************************************************/
unsigned char mcu_wakeup_leokey_ble(void)
{
    unsigned short length = 0;
    unsigned char  tx_buf[16];
        
    my_memset(tx_buf, 0x5A, sizeof(tx_buf));
    
    leokey_ble_uart_write_data(tx_buf, sizeof(tx_buf));
    // 具体延时到正常接收第一帧数据的时间请测试
    delay_1ms(50);
        
    return SUCCESS;
}






/*****************************************************************************
函数名称 : data_handle
功能描述 : 数据帧处理

返回参数 : 无
*****************************************************************************/
int data_handle(void)
{
    unsigned short dp_len;
    unsigned char ret;
    unsigned short i, total_len;
    unsigned char cmd_cmd = leokey_ble_uart_rx_buf[FRAME_CMD];

    total_len = leokey_ble_uart_rx_buf[LENGTH] * 0x100;
    total_len += leokey_ble_uart_rx_buf[LENGTL];
    
    
    switch (cmd_cmd)
    {
        //0x00：唤醒指令
        case WAKEUP_CMD:    

            break;
            
        //0x01：广播控制指令
        case LEOKEY_BLE_ADV_CMD:      
            LeoKey_Printf("LEOKEY_BLE_ADV_CMD  ACK \r\n");
            break;
        
        //0x02：查询leokey_ble工作状态
        case LEOKEY_BLE_STATE_CMD:       
      
            break;

        //0x10：配置leokey_ble模块
        case LEOKEY_BLE_CFG_CMD: 
            //LeoKey_Printf("ble_cmd_data_handle \r\n");            
            ble_cmd_data_handle( (unsigned char*)&leokey_ble_uart_rx_buf[DATA_START] , total_len);
            break;
        
        //0x11：配置leokey_ble模块
        case LEOKEY_BLE_MASTER_QUERY: 
            //LeoKey_Printf("ble_cmd_data_handle \r\n");            
            ble_master_query_info( (unsigned char*)&leokey_ble_uart_rx_buf[DATA_START] , total_len);      
            break;
               

        //0x30：设置锁板MCU时间
        case SET_TIMESTAMP_CMD:      
            LeoKey_Printf("set mcu timestamp. \r\n");
            ble_write_mcu_rtctime( (unsigned char*)&leokey_ble_uart_rx_buf[DATA_START] );          
            break;

        //0x32：leokey_ble模块恢复出厂成功
        case FACTORY_RESET_CMD:       
            LeoKey_Printf("FACTORY_RESET_CMD  ACK \r\n");
            break;

        //0x33：获取蓝牙模块和APP绑定的UserKey用于计算临时密码
        case GET_USER_KEY:      
            LeoKey_Printf("get user key. \r\n");
            Hexdump_Debug((unsigned char*)&leokey_ble_uart_rx_buf[DATA_START], 17, ' ');        
            break;        

        default:
            LeoKey_Printf("error!!! unknow cmd !!!\r\n"); 
            break;
    }
    
    rx_in = 0;
    rx_length = 0;
    my_memset((void *) leokey_ble_uart_rx_buf, 0, sizeof(leokey_ble_uart_rx_buf));    //清除接收缓存
    return 1;
}




/*****************************************************************************
函数名称 : mcu_enable_add_leokey_adv
功能描述 : 使能可添加广播
输入参数 : 无
返回参数 : 无
使用说明 : 让leokey_ble进入可添加状态，若已添加过，leokey_ble会忽略
*****************************************************************************/
void mcu_enable_add_leokey_adv(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x20);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_ADV_CMD, length);
}



/*****************************************************************************
函数名称 : mcu_enable_open_lock_leokey_adv
功能描述 : 使能可开锁广播
输入参数 : 无
返回参数 : 无
使用说明 : 让leokey_ble进入可开锁状态，若未添加过APP，leokey_ble会忽略
*****************************************************************************/
void mcu_enable_open_lock_leokey_adv(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x21);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_ADV_CMD, length);
}



/*****************************************************************************
函数名称  : mcu_disable_leokey_adv
功能描述  : 关闭leokey_ble广播
输入参数  : 无
返回参数  : 无
*****************************************************************************/
void mcu_disable_leokey_adv(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x22);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_ADV_CMD, length);

}




/*****************************************************************************
函数名称 : leokey_ble_factory_reset
功能描述 : leokey_ble模块恢复出厂，即删除已经绑定的UserKey
输入参数 : 无
返回参数 : 无
*****************************************************************************/
void leokey_ble_factory_reset(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x01);
    
    leokey_ble_uart_write_frame(FACTORY_RESET_CMD, length);
}


/*****************************************************************************
函数名称 : get_leokey_ble_user_key
功能描述 : UserKey 长度16字节
输入参数 : 无
返回参数 : 无
使用说明 : 获取蓝牙模块和APP绑定的UserKey用于计算临时密码
*****************************************************************************/
void get_leokey_ble_user_key(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x01);
    
    leokey_ble_uart_write_frame(GET_USER_KEY, length);
}


void get_leokey_ble_mac_addr(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x01);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_MASTER_QUERY, length);
}

void get_leokey_ble_user_key_b(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x02);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_MASTER_QUERY, length);
}

void get_leokey_ble_soft_version(void)
{
    unsigned short length = 0;
    
    length = set_leokey_ble_uart_byte(length, 0x03);
    
    leokey_ble_uart_write_frame(LEOKEY_BLE_MASTER_QUERY, length);
}





#ifdef SUPPORT_MCU_RTC_CHECK


/*****************************************************************************
函数名称 : Is_Leap_Year
功能描述 : 判断闰年/平年
输入参数 : pyear：年份
返回参数 : 1：闰年；0：平年
使用说明 : 调用该函数判断年份是否为闰年
*****************************************************************************/
static unsigned char Is_Leap_Year(unsigned int pyear)
{
    if (pyear % 4 == 0)//首先需能被4整除
    {
        if (pyear % 100 == 0)
        {
            if (pyear % 400 == 0) return 1;//世纪闰年。如果以00结尾，还要能被400整除
            else return 0;
        }
        else
            return 1;    //普通闰年。能被4整除但不能被100整除的年份
    }
    else
        return 0;
}

/*****************************************************************************
函数名称 : RTC_Get
功能描述 : 计算时间
输入参数 : secCount：时间戳总秒数
           *calendar：时间结构体
返回参数 : 0：计算完成
使用说明 : 根据时间戳计算时间值
*****************************************************************************/
static unsigned char RTC_Get(unsigned int secCount, _calendar_obj *calendar)
{
    static unsigned int dayCount = 0;
    unsigned int tmp = 0;    //天数
    unsigned int tmp1 = 0;    //年份 or 月份

    tmp = secCount / 86400;//得到天数(24hour * 3600sec)

    if (dayCount != tmp)//超过一天
    {
        dayCount = tmp;
        tmp1 = 2000;//从2000年开始

        while (tmp >= 365)    //超过一年
        {
            if (Is_Leap_Year(tmp1))//是闰年
            {
                if (tmp >= 366)
                    tmp -= 366;//减掉闰年的天数
                else
                {
                    //    tmp1++;
                    break;
                }
            }
            else
                tmp -= 365;//减掉平年的天数
            tmp1++;    //年份加1
        }
        calendar->w_year = tmp1;//得到年份
        tmp1 = 0;

        while (tmp >= 28)//超过一个月
        {
            if (Is_Leap_Year(calendar->w_year) && tmp1 == 1)//当年是闰年且轮循到2月
            {
                if (tmp >= 29)    //闰年二月为29天
                    tmp -= 29;    //减掉闰年二月天数
                else
                    break;
            }
            else
            {
                if (tmp >= mon_table[tmp1])//平年
                    tmp -= mon_table[tmp1];    //减掉月份天数（非闰年二月）
                else
                    break;
            }
            tmp1++;
        }
        calendar->w_month = tmp1 + 1;    //得到月份，tmp1=0表示1月，所以要加1
        calendar->w_date = tmp + 1;    //得到日期，因为这一天还没过完，所以tmp只到其前一天，但是显示的时候要显示正常日期
    }
    tmp = secCount % 86400;//得到不足一天的总秒钟数
    calendar->hour = tmp / 3600;//小时
    calendar->min = (tmp % 3600) / 60;//分钟
    calendar->sec = (tmp % 3600) % 60;//秒

    return 0;
}

/*****************************************************************************
函数名称 : leokey_ble_timestamp_to_time
功能描述 : 计算时间
输入参数 : 无
返回参数 : 时间结果
使用说明 : 根据时间戳计算时间值
*****************************************************************************/
void leokey_ble_timestamp_to_time(void)    //unsigned char *tsp)
{
    unsigned int time_stamp = byte_to_int(timestamp);
    RTC_Get(time_stamp, &_time);    //根据时间戳计算
}

#endif




#ifdef SUPPORT_MCU_FIRM_UPDATE
/*****************************************************************************
函数名称 : assic_to_hex
功能描述 : ASSIC码转成hex
输入参数 : ASSIC值
返回参数 : 十进制值
使用说明 : 用于计算0~9的ASSIC
*****************************************************************************/
char assic_to_hex(unsigned char assic_num)
{
    if(assic_num<0x30 && assic_num > 0x39)	//0~9
        return -1;
    else
        return assic_num % 0x30;
}
/*****************************************************************************
函数名称 : strcmp_barry
功能描述 : 比较字符串
输入参数 : *str1:字符串1
                     *str2:字符串2
返回参数 : 比较结果
使用说明 : 比较字符串是否相等
*****************************************************************************/
int strcmp_barry(unsigned char *str1,unsigned char *str2)
{
    int ret=0;
    while( !(ret = *(unsigned char*)str1 - *(unsigned char*)str2 ) && *str1 )
     {
         str1++;
         str2++;
     }
     if(ret < 0)	//str1 < str2
            return -1;
     else if(ret > 0)	//str1 > str2
            return 1;
     return 0;	//str1 == str2
}



#endif
